package com.guosen.web.mocker

/**
 * Created by kerry on 2016/10/25.
 * parse mete data
 */
class Collecter {
    /*
    mbegin
        method=get
        des=xxx
        url=/a/test
        in:
            age=i+ // 年龄
            amount=f? // 金额
            name=s // 姓名
        out:
            statusCode=i+
            data={}
                ,size=i+
                ,list=[]
                    ,,people={}
                        ,,,name=i+ // 年龄
                        ,,,birth=d+ // 生日
                    ,,class={}
                        ,,,num=i+ // 班级
    mend
     */

    public static List parse(List lines) {
        List r = []

        final String blockBegin = 'mbegin'
        final String blockEnd = 'mend'

        boolean isBegin = false

        List sub = []
        for (line in lines) {
            line = line.trim()
            if (line.startsWith(blockBegin)) {
                sub.clear()
                isBegin = true
                continue
            }

            if (line.startsWith(blockEnd)) {
                isBegin = false
                Map one = parseOne(sub)
                r << one
                continue
            }

            if (isBegin) {
                sub << line
            }
        }
        r
    }

    static Map parseOne(List lines) {
        Map r = [:]
        List sub = []

        int cc = 0
        for (one in lines) {
            cc++
            if (one ==~ /^(method|des|url)=.+$/) {
                def arr = one.split('=')
                r[arr[0]] = arr[1]
                continue
            }

            if (one == 'in:') {
                continue
            } else if (one == 'out:') {
                r.input = parseObj(sub)
                sub.clear()
                continue
            }

            sub << one
            if (cc == lines.size()) {
                r.output = parseObj(sub)
            }
        }

        r
    }

    // get output json meta data
    static List parseObj(List lines) {
        def pat = /([^=]+)=([^\/]+)(\/\/.+)?/
        lines.collect {
            def mat = it =~ pat
            if (!mat)
                return null

            def group = mat[0]
            String key = group[1].trim()
            String type = group[2].trim()
            String des = group[3] ? group[3].trim() : null

            boolean isRequired = type ==~ /^.+[?*+]$/
            String typeRaw = isRequired ? type[0..-2] : type
            String require = isRequired ? type[-1] : ''

            Map r = [:]
            r.key = key
            r.type = typeRaw
            r.require = require
            r.des = des ? des.replaceAll('/', '').trim() : null
            r.level = key.count(',')
            r
        }
    }

    static Object mockValue(String type) {
        if (type == 'i')
            return 1
        else if (type == 'f')
            return 1.00
        else if (type == 'd')
            return new Date()
        else if (type == 's')
            return 'test'
        else
            return null
    }

    static void mockFill(Map r, List list) {
        list.each {
            String key = it.key.replaceAll(',', '')
            if (it.type == '{}') {
                r[key] = [:]
            } else if (it.type == '[]') {
                r[key] = []
            } else {
                r[key] = mockValue(it.type)
            }
        }
    }

    // list -> output meta data list
    static Map mockOne(List list, List allList, int level = 0) {
        if (!list)
            return null

        Map r = [:]

        mockFill(r, list.grep { it.level == level })
        for (one in r) {
            Map subOne = mockOne(getSubListByKey(allList, one.key), allList, level + 1)
            if (!subOne)
                continue

            if (one.value instanceof List) {
                one.value << subOne
            } else if (one.value instanceof Map) {
                one.value.putAll(subOne)
            }
        }
        r
    }

    /// get index by key
    static int getIndexByKeyRaw(List list, String key) {
        int i = 0
        for (; i < list.size(); i++) {
            Map it = list[i]
            String keyRaw = it.key.replaceAll(',', '')
            if (keyRaw == key)
                return i
        }

        return -1
    }

    // key must be unique
    static List getSubListByKey(List list, String key) {
        int begin = getIndexByKeyRaw(list, key)
        if (begin == -1)
            return null
        if (begin == list.size() - 1)
            return null

        Map target = list[begin]
        int level = target.level

        int i = begin + 1
        int end = -1
        for (; i < list.size(); i++) {
            int levelIt = list[i].level
            if (level == levelIt) {
                end = i - 1
                break
            }
        }

        list[begin..end]
    }
}
